package com.tenbent.product.base.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tenbent.product.base.config.swagger.SwaggerConfig;
import com.tenbent.product.base.spring.interceptor.TenbentIntecepter;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.*;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.stereotype.Service;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import java.io.IOException;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * webmvc配置类
 *
 * @author Randy
 *
 *         Created by ThinkPad on 2017/7/24.
 */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.tenbent.product.center" }, excludeFilters = {
		@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Service.class) })
// 引入swagger配置 swagger属于mvc配置
@Import(SwaggerConfig.class)
// 开启security方法级认证 只针对controller层的方法级
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebConfig extends WebMvcConfigurerAdapter {

	/**
	 *
	 * 配置jsp视图解析器
	 */
	@Bean
	public ViewResolver viewResolver() {

		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setPrefix("/WEB-INF/views/");
		viewResolver.setSuffix(".jsp");
		viewResolver.setViewClass(JstlView.class);
		return viewResolver;
	}

	/**
	 *
	 * 配置文件上传视图解析器
	 */
	@Bean
	public MultipartResolver multipartResolver() throws IOException {
		return new StandardServletMultipartResolver();
	}

	/**
	 * 异常处理视图解析
	 *
	 **/
	@Bean
	public ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver() {
		return new ExceptionHandlerExceptionResolver();
	}

	/**
	 * 表单验证配置Bean
	 *
	 */
	@Bean
	public LocalValidatorFactoryBean validator(ResourceBundleMessageSource messageSource) {

		LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
		validator.setProviderClass(HibernateValidator.class);
		validator.setValidationMessageSource(messageSource);
		return validator;
	}

	/**
	 * 配置验证信息资源位置Bean
	 *
	 * 定义国际化资源文件查找规则 ，各种messages.properties
	 * 
	 */
	@Bean
	public ResourceBundleMessageSource messageSource() {

		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		String[] baseNames = new String[] { "validate_messages", "messages" };
		messageSource.setBasenames(baseNames);
		messageSource.setDefaultEncoding("UTF-8");
		// 如果像获取@Size(min,max)属性的值就必须设置为false
		messageSource.setUseCodeAsDefaultMessage(false);
		return messageSource;
	}

	/**
	 * 本地化资源处理器 国际化 (三种处理器配置方式选择一种 cookie，session，Accept-Language)
	 */
	@Bean
	public LocaleResolver localeResolver() {

		// 本地化基于Cookie国际化 请求request参数locale=zh_CN或locale=en_US
		// LocaleResolver localeResolver = new CookieLocaleResolver();
		// 本地化基于Session国际化 请求session参数locale=zh_CN或locale=en_US
		// LocaleResolver localeResolver = new SessionLocaleResolver();
		// 本地化基于请求头国际化 请求头设置
		// Accept-Language=cn-zh,cn;q=0.5或Accept-Language=en-us,en;q=0.5
		LocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
		return localeResolver;
	}

	/**
	 * 本地改变拦截器 国际化
	 */
	@Bean
	public LocaleChangeInterceptor localeChangeInterceptor() {
		return new LocaleChangeInterceptor();
	}

	/**
	 * 自定义拦截器
	 */
	@Bean
	public TenbentIntecepter tenbentIntecepter() {
		return new TenbentIntecepter();
	}

	/**
	 * 类型转换器
	 *
	 * StringHttpMessageConverter
	 */
	@Bean
	public StringHttpMessageConverter stringHttpMessageConverter() {
		return new StringHttpMessageConverter(Charset.forName("UTF-8"));
	}

	/**
	 * 类型转换器(MappingJackson2HttpMessageConverter)
	 *
	 * 处理@RequestBody @ResponseBody 返回值转换json
	 */
	@Bean
	public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {

		MappingJackson2HttpMessageConverter mappingJackson2MessageConverter = new MappingJackson2HttpMessageConverter();
		mappingJackson2MessageConverter.setSupportedMediaTypes(getMediaTypes());
		ObjectMapper objectMapper = new ObjectMapper();
		// 处理responseBody 里面日期类型
		objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
		// objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		// 此属性是为了在作为@ResponseBody时对null的值对应的属性进省略输出，默认以null的方式输出。(这种是将字段为null的清理掉不在结果Json中显示出来)
		objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		mappingJackson2MessageConverter.setObjectMapper(objectMapper);
		return mappingJackson2MessageConverter;
	}

	/**
	 * 类型装换器(Jaxb2RootElementHttpMessageConverter)
	 *
	 * 处理xml数据转换
	 */
	@Bean
	public Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter() {
		Jaxb2RootElementHttpMessageConverter jaxb2RootElementConverter = new Jaxb2RootElementHttpMessageConverter();
		jaxb2RootElementConverter.setSupportedMediaTypes(getMediaTypes());
		return jaxb2RootElementConverter;
	}

	/**
	 * 类型转换器(MappingJackson2XmlHttpMessageConverter)
	 *
	 */
	@Bean
	public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter() {
		return new MappingJackson2XmlHttpMessageConverter();
	}

	@Override
	public Validator getValidator() {
		return validator(messageSource());
	}

	/**
	 *
	 * 配置请求拦截器(类似过滤器)
	 */
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(localeChangeInterceptor());
		registry.addInterceptor(tenbentIntecepter());
	}

	/**
	 * 配置默认的sevelt对没有匹配上的资源使用默认的servlet
	 *
	 * 例如 css ，image，js等
	 *
	 */
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}

	/**
	 *
	 * 配置请求参数转换json等数据格式(追加的方式)
	 *
	 * 注意，如果spring默认配置了converters，在后面追加相同的converters不会生效
	 *
	 * 例如 mappingJackson2HttpMessageConverter 针对date类型转换日期，无效就是此原因。
	 *
	 * 一般适用自定义转换器。
	 */
	// @Override
	// public void extendMessageConverters(List<HttpMessageConverter<?>>
	// converters) {
	// converters.add(stringHttpMessageConverter());
	// // 处理@RequestBody 或 @ResponseBody 入参json格式和出参json格式
	// converters.add(mappingJackson2HttpMessageConverter());
	// converters.add(mappingJackson2XmlHttpMessageConverter());
	// converters.add(jaxb2RootElementHttpMessageConverter());
	// }

	/**
	 * 配置请求参数转换json等数据格式(替换的方式)
	 *
	 * 如果想对默认的转换器不能满足需求，(例如对日期数据进行格式化) 则需要重新配置。
	 */
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		converters.add(stringHttpMessageConverter());
		// 处理@RequestBody 或 @ResponseBody 入参json格式和出参json格式
		converters.add(mappingJackson2HttpMessageConverter());
		converters.add(mappingJackson2XmlHttpMessageConverter());
		converters.add(jaxb2RootElementHttpMessageConverter());
	}

	/**
	 *
	 * 配置静态资源不被拦截为请求
	 * <p>
	 * <可以在jsp中使用/js/**的方式访问/js/下的内容> <可以在jsp中使用/css/**的方式访问/css/下的内容>
	 * <可以在jsp中使用/image/**的方式访问/image/下的内容> </p
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/js/**").addResourceLocations("/js/");
		registry.addResourceHandler("/css/**").addResourceLocations("/css/");
		registry.addResourceHandler("/image/**").addResourceLocations("/image/");
		// 以下部分为swagger集成配置
		registry.addResourceHandler("swagger-ui.html")
				.addResourceLocations("classpath:/META-INF/resources/swagger-ui.html");
		registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
	}

	/**
	 * 设置转换器的 MediaType
	 */
	private List<MediaType> getMediaTypes() {
		List<MediaType> mediaTypes = new ArrayList<>();
		mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
		return mediaTypes;
	}

}
